#pragma once 

#include <iostream>
#include <string>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include "logMessage.hpp"
#include "threadpool.hpp"
#include "Task.hpp"

#define BUF_NUM 1024

namespace tcps
{
    enum
    {
        USAGE = 1,
        SOCK_ERR,
        BIND_ERR,
        LISTEN_ERR  
    };

    class TcpServer;

    const std::string gip = "0.0.0.0";

    class ThreadData
    {
    public:
        ThreadData(TcpServer* td, int sock)
        :_this(td), _sock(sock)
        {}
    public:
        TcpServer* _this;
        int _sock;
    };

    class TcpServer
    {
    public:
        TcpServer(const uint16_t & serverport /*, const std::string &serverip = gip*/)
        :_listensockfd(-1), _serverport(serverport) /*, _serverip(serverip)*/
        {}
        void initTcpServer()
        {
            //step 1:构建一个服务器监听套接字
            _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
            if(_listensockfd < 0)
            {
                logMessage(FATAL, "socket create error");
                exit(SOCK_ERR);
            }
            logMessage(NORMAL, "socket create success");
            //step 2:将服务器监听套接字与对应的端口进行绑定
            struct sockaddr_in local;
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_serverport);
            local.sin_addr.s_addr = INADDR_ANY;
            
            if(bind(_listensockfd, (struct sockaddr*)&local, sizeof(local)) != 0)
            {
                logMessage(FATAL, "socket bind error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "socket bind success");

            //step 3:开始监听
            if(listen(_listensockfd, 4) != 0)
            {
                logMessage(FATAL, "socket listen error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "socket listen success");
        }
        void runTcpServer()
        {
            //version 2.2:mul process by signal
            signal(SIGCHLD, SIG_IGN);
            //step 4:开始与客户端套接字进行链接
            for(;;)
            {
                struct sockaddr_in client;
                socklen_t clientlen = sizeof(client);
                int sock = accept(_listensockfd, (struct sockaddr*)&client, &clientlen);
                if(sock < 0) 
                {
                    logMessage(ERROR, "socket accept error");
                    continue;
                }
                logMessage(NORMAL, "socket accept success: %d", sock);
                // std::cout << "socket: " << sock << std::endl;
                //version 1:single process
                //接受客户端的信息
                // serviceIO(sock, client);
                // //最后要把这个刚建的套接字关掉，否则可能会有套接字泄露问题
                // close(sock);

                //version 2.1:mul process by grandson process
                // pid_t id = fork();
                // if(id == 0)//child
                // {
                //     // if(fork()>0) exit(0);//此时创建一个孙子进程，让这个孙子进程成为一个孤儿进程，由操作系统来回收对应的资源
                //     // 通过忽略该信号可以使该进程不需要由父进程来回收，最后交给 OS 来完成回收，而且多次创建进程对 OS 开销过大
                //     serviceIO(sock);
                //     close(sock);
                // }
                
                //version 3:mul thread
                // pthread_t pid;
                // ThreadData* td = new ThreadData(this, sock);
                // pthread_create(&pid, nullptr, handler, td);

                //version 4:threadpool
                Task t(sock, serviceIO);
                ThreadPool<Task>::getInstance()->run();
                ThreadPool<Task>::getInstance()->push(t);

            }
        }
        static void* handler(void* args)
        {
            //由OS回收这部分资源
            pthread_detach(pthread_self());
            ThreadData* td = static_cast<ThreadData*>(args);
            // td->_this->serviceIO(td->_sock);
            serviceIO(td->_sock);
            close(td->_sock);
            delete td;
            return nullptr;
        }
        // void serviceIO(int sock/*, struct sockaddr_in &client*/)
        // {
        //     char buffer[BUF_NUM];
        //     /*std::string clientip = inet_ntoa(client.sin_addr);
        //     uint16_t clientport = ntohs(client.sin_port);*/
        //     while(true)
        //     {
        //         std::string msg;
        //         int n = read(sock, buffer, sizeof(buffer)-1);
        //         msg = buffer;
        //         if(n > 0) //std::cout << clientip << "[" << clientport << "]" << msg << std::endl;
        //             std::cout << msg << std::endl;
        //         else if(n == 0) break;//说明客户端退出了
        //         //服务端将客户端信息进行回显
        //         msg += " server[echo]";
        //         write(sock, msg.c_str(), msg.size());
        //     }
        // }
        ~TcpServer()
        {
            close(_listensockfd);
        }
    private:
        std::string _serverip;
        uint16_t _serverport;
        int _listensockfd;//用于监听的文件描述符//监听的文件描述符相当于拉客的服务员，只需要一个就可以了
    };
}